package br.ufrn.opencopi.util;

import java.util.Hashtable;
import java.util.Random;

/**
 * This class controll ports in use to OpenCOPI listeners (ports for underlay middleware connexion)
 * @author Fred
 *
 */
public class PortController {

	static Hashtable portsInUse;
	static Random generator;
	static int quantityPorts;
	//Ports interval: 60000 to 65000
	private static int QUANTPORTS = 5000;
	private static int INITIALPORT = 60000;

	/**
	 * Basic constructor
	 *
	 */
	public PortController(){
		portsInUse = new Hashtable();
		//generator = new Random(1000);
		generator = new Random();
		quantityPorts = QUANTPORTS;
	}

	/**
	 * Constructor with ControllerPort limit specific
	 */
	public PortController(int quantityPorts){
		this();
		this.quantityPorts = quantityPorts;
	}

	/**
	 * Create a random port  60000 e 60000+limit
	 * @return randomPort
	 */
	private static int getRandomPort(){
		return INITIALPORT+generator.nextInt(quantityPorts);
	}

	/**
	 * recursive function to find a new port without use
	 * @return port
	 */
	public static int getValidPort(){
		int port = getRandomPort();
		String portString = String.valueOf(port);
		if(!portsInUse.containsKey(portString)){
			reservePort(portString);
			return port;
		}else{
			getValidPort();
		}
		return port;
	}

	/**
	 * Liberate a spscific port
	 * @param port
	 */
	public static void liberatePort(int port){
		liberatePort(String.valueOf(port));
	}

	/**
	 * Liberate a spscific port
	 * @param port
	 */
	public static void liberatePort(String port){
		portsInUse.remove(port);
	}

	/**
	 * set a port in hashtable
	 * @param port
	 */
	private static void reservePort(String port){
		portsInUse.put(port, port);
	}

	/**
	 * Allocate a port to client. If the port is used then it get other port (using getValidPort)
	 * @param i
	 * @return
	 */
	public static int allocatePort(String i){
		if(portsInUse.containsKey(i)){
			return getValidPort();
		}else{
			reservePort(i);
			return Integer.parseInt(i);
		}
	}

}
